#include "hiddevice.h"
#include <QDebug>

HIDDevice::HIDDevice(QObject *parent) : QObject(parent), device(nullptr), isOpen(false)
{
}

HIDDevice::~HIDDevice()
{
    close();
}

bool HIDDevice::initialize()
{
    return (hid_init() == 0);
}

void HIDDevice::exit()
{
    hid_exit();
}

QList<HIDDevice::DeviceInfo> HIDDevice::enumerateDevices(unsigned short vendorId, unsigned short productId)
{
    QList<DeviceInfo> deviceList;
    struct hid_device_info *devs, *cur_dev;
    
    devs = hid_enumerate(vendorId, productId);
    cur_dev = devs;
    while (cur_dev) {
        DeviceInfo info;
        info.vendorId = cur_dev->vendor_id;
        info.productId = cur_dev->product_id;
        info.path = QString::fromUtf8(cur_dev->path);
        info.serialNumber = QString::fromWCharArray(cur_dev->serial_number);
        info.manufacturerString = QString::fromWCharArray(cur_dev->manufacturer_string);
        info.productString = QString::fromWCharArray(cur_dev->product_string);
        info.releaseNumber = cur_dev->release_number;
        info.interfaceNumber = cur_dev->interface_number;
        
        deviceList.append(info);
        cur_dev = cur_dev->next;
    }
    hid_free_enumeration(devs);
    
    return deviceList;
}

bool HIDDevice::open(const QString& path)
{
    if (device) {
        close();
    }
    
    device = hid_open_path(path.toUtf8().constData());
    if (device) {
        isOpen = true;
        emit deviceConnected();
        return true;
    }
    return false;
}

bool HIDDevice::open(unsigned short vendorId, unsigned short productId)
{
    if (device) {
        close();
    }
    
    device = hid_open(vendorId, productId, nullptr);
    if (device) {
        isOpen = true;
        emit deviceConnected();
        return true;
    }
    return false;
}

void HIDDevice::close()
{
    if (device) {
        hid_close(device);
        device = nullptr;
        isOpen = false;
        emit deviceDisconnected();
    }
}

bool HIDDevice::write(unsigned char *data, size_t data_length)
{
    int result(0),sendLen(0);
    if(device)
    {
        unsigned char dataTemp[64];
        int currentLen(0);
        dataTemp[0] = 0x02;
        while(result < (int)data_length)
        {
//            currentLen = std::min((int)data_length - result,61);
            currentLen = std::min((int)data_length - result,59);
            memcpy(dataTemp+2,data+result,currentLen);
            dataTemp[1] = (unsigned char)(currentLen);
            sendLen = hid_write(device,dataTemp,currentLen+2);
//            this->thread()->msleep(5);
            if(sendLen <= 0)
                return -1;
            result+=currentLen;
        }
    }
    return result;
}

bool HIDDevice::write1(unsigned char *data, size_t data_length)
{
    int result(0),sendLen(0);
    if(device)
    {
        unsigned char dataTemp[64];
        int currentLen(0);
        dataTemp[0] = 0x02;
        while(result < (int)data_length)
        {
//            currentLen = std::min((int)data_length - result,61);
            currentLen = std::min((int)data_length - result,59);
            memcpy(dataTemp+2,data+result,currentLen);
            dataTemp[1] = (unsigned char)(currentLen);
            sendLen = hid_write(device,dataTemp,currentLen+2);
//            this->thread()->msleep(5);
            if(sendLen <= 0)
                return -1;
            result+=currentLen;
        }
    }
    return result;
}

bool HIDDevice::read(unsigned char *data, size_t data_length, const int milliseconds)
{
    unsigned char *data1 = new unsigned char[data_length];
    int result(-1);
    if(device)
        result = hid_read_timeout(device,data1,data_length, milliseconds);
    if(result != 0)
    {
        result = data1[1];
        if(result > (int)data_length)
        {
            result = -1;
        }
        if(result != -1)
            memcpy(data,data1+2,result);
    }
    delete[] data1;
    return result;
}

//bool HIDDevice::write(const QByteArray& data)
//{
//    if (!device || !isOpen) {
//        emit errorOccurred("设备未连接");
//        return false;
//    }
    
//    int result = hid_write(device, reinterpret_cast<const unsigned char*>(data.constData()), data.size());
//    if (result == -1) {
//        emit errorOccurred(getLastError());
//        return false;
//    }
//    return true;
//}

//bool HIDDevice::read(QByteArray& data, int timeout)
//{
//    if (!device || !isOpen) {
//        emit errorOccurred("设备未连接");
//        return false;
//    }
    
//    unsigned char buffer[BUFFER_SIZE];
//    int result = hid_read_timeout(device, buffer, sizeof(buffer), timeout);
    
//    if (result > 0) {
//        data = QByteArray(reinterpret_cast<char*>(buffer), result);
//        emit dataReceived(data);
//        return true;
//    } else if (result == -1) {
//        emit errorOccurred(getLastError());
//    }
//    return false;
//}

bool HIDDevice::sendFeatureReport(const QByteArray& data)
{
    if (!device || !isOpen) return false;
    return (hid_send_feature_report(device, 
        reinterpret_cast<const unsigned char*>(data.constData()), 
        data.size()) != -1);
}

bool HIDDevice::getFeatureReport(QByteArray& data, size_t reportId)
{
    if (!device || !isOpen) return false;
    
    unsigned char buffer[BUFFER_SIZE];
    buffer[0] = reportId;
    
    int result = hid_get_feature_report(device, buffer, sizeof(buffer));
    if (result > 0) {
        data = QByteArray(reinterpret_cast<char*>(buffer), result);
        return true;
    }
    return false;
}

QString HIDDevice::getLastError() const
{
    if (!device) return QString();
    const wchar_t* error = hid_error(device);
    return error ? QString::fromWCharArray(error) : QString();
}

QString HIDDevice::getManufacturerString() const
{
    if (!device) return QString();
    wchar_t buffer[255];
    if (hid_get_manufacturer_string(device, buffer, sizeof(buffer)) == 0) {
        return QString::fromWCharArray(buffer);
    }
    return QString();
}

QString HIDDevice::getProductString() const
{
    if (!device) return QString();
    wchar_t buffer[255];
    if (hid_get_product_string(device, buffer, sizeof(buffer)) == 0) {
        return QString::fromWCharArray(buffer);
    }
    return QString();
}

QString HIDDevice::getSerialNumberString() const
{
    if (!device) return QString();
    wchar_t buffer[255];
    if (hid_get_serial_number_string(device, buffer, sizeof(buffer)) == 0) {
        return QString::fromWCharArray(buffer);
    }
    return QString();
} 
